/**  ------------------------------ 数据解析及命令参数转换js插件开发说明 --------------------------------------------------------------
 * 一、约定：
 * 1.每一个设备类型对应一个js插件文件，文件位置：相对于springboot的resources目录下面的路径(/js/plugin/<devtype>.js);
 * 2.js插件文件名为<devtype>.js，devtype为设备类型编号，如：haitong_ac_v1;
 * 3.js插件中包括一个上报数据解析方法和N个（N>=0）控制命令转换方法。
 * 
 * 二、设备上报业务数据（metedata）解析：
 * 1、方法名固定为:funcupdataparse. 
 * 2、入参固定为:JSParam，定义参见com.zte.claa.inficombo.csa.app.service.jsplugin.JSParam，包括如下方法：
 *	(2.1) getDevtypeid() -->获取当前设备类型ID；
 *	(2.2) getDeveui()    -->获取对应设备编号deveui；
 *	(2.3) getDevport()   -->获取设备上报的port，通常用不到；
 *	(2.4) getParas()     -->获取指标映射表：Map<String, Object>，对于上报数据,只有一个参数项：uppayload，value是byte[]，终端上报的原始码流.
 *	(2.5) getPara(pname) -->获取指定名称的参数，返回Object对象；
 *  (2.6) getAppeui()    -->获取对应的appeui参数；
 * 3、解析结果分为四种情况：metedata或alarmdata或Map<String, Object>或null。
 * (3.1)如果是无效数据，则返回null;
 * (3.2)如果是metedata，则解析结果为json字符串，形如：{"f1name":f1val, "f2name":f2val, ...}，其中fnname和当前设备类型的业务模型定义一致；
 * (3.3)如果是告警AlarmData，则返回的对象为AlarmData对象，该java类型的定义参见:com.zte.claa.inficombo.csa.app.model.redis.AlarmData.
 * (3.4)如果上报的数据中同时包括metedata和alarm或需要返还ackcmd，则返回Map<String, Object>，map中包括最多5个item，分别是：
 *      (3.4.1)key="metedata", value=metedata对应的json字符串，和3.2一致；
 *      (3.4.2)key="alarm", value=AlarmData对象，和3.3一致。
 *      (3.4.3)key="ackcmd",value=AppCmdWrapper对象，详见com.zte.claa.inficombo.csa.app.service.rptparse.AppCmdWrapper定义.
 *      (3.4.4)key="metedatalist", value=ArrayList<String>, 列表item=metedata对应的json字符串，和3.2一致；
 *      (3.4.5)key="alarmlist", value=ArrayList<AlarmData>, 列表item=AlarmData对象，和3.3一致。
 * 
 * 三、控制指令转换说明：
 * 1、每一个命令控制字对应一个function，function名称=控制字名称;
 * 2、每一个控制字对应的func入参统一为jsParam，定义同数据解析，其中getParas()方法获取命令控制参数：
 * 	  (2.4) getParas(), 返回值：Map<String, Object>，key=[P1,....,Pn],val=P1~Pn对应的参数值；
 * 3、控制命令转换结果为byte[]。
 * 
 * 	 转换时可以使用的jdk8所提供的各类java对象，通常是如下List对象；JSONObject是json转换对象类，参照本例使用。 
 *  
 *  ---------------------------------------------------------------------------------------------------------------------
 *  常用java类型引用：
 *  var ByteBuffer = Java.type('java.nio.ByteBuffer');
 *  var List = Java.type('java.util.ArrayList');
 *  var String = Java.type('java.lang.String');
 *  var JSONObject = Java.type('org.json.JSONObject');
 */ 
var JSONObject = Java.type('org.json.JSONObject');
var String = Java.type('java.lang.String');
var HashMap = Java.type('java.util.HashMap');
var LogPrint = Java.type('com.zte.claa.inficombo.csa.app.service.rptparse.JsLogPrint');
var AlarmData = Java.type('com.zte.claa.inficombo.csa.app.model.redis.AlarmData');
var CRC16M = Java.type('com.zte.claa.inficombo.csa.app.service.rptparse.CRC16M');
var AppCommand = Java.type('com.zte.claa.inficombo.csa.app.service.rptparse.AppCommand');
var AppCmdWrapper = Java.type('com.zte.claa.inficombo.csa.app.service.rptparse.AppCmdWrapper');
var ConfDataRequest = Java.type('com.zte.claa.inficombo.csa.app.service.rptparse.ext.claa.ConfDataRequest');
var LocRawData = Java.type('com.zte.claa.inficombo.csa.app.service.rptparse.LocRawData');
var AlarmData = Java.type('com.zte.claa.inficombo.csa.app.model.redis.AlarmData');
var DevVersionUpdateLog = Java.type('com.zte.claa.inficombo.csa.app.model.version.DevVersionUpdateLog');

/**
 * 1. 上报数据解析方法，统一固定命名为：funcupdataparse
 * 入参：JSParam
 * 
 */
function funcupdataparse(jsParam){
	var bs = jsParam.getPara('uppayload');
	var projectid = jsParam.getProjectid();
	var anchor_eui = jsParam.getDeveui();
	var rptdatastr = new String(bs, 'utf-8');
	var logger = new LogPrint();	
	var outMap = new HashMap();
	var locrawdata = new LocRawData();//定位消息对象
	retStr = rptdatastr.trim();	
	logger.info("Js parsed gprs_claa_locanchor sourcestr:"+retStr);	
	if(retStr.indexOf("keepalive")!=-1){
		var appwrapper = new AppCmdWrapper();
		buildDevAckCmd(jsParam, appwrapper);
		outMap.put("ackcmd",appwrapper);
		return outMap;
	}
	
	if(!retStr.startsWith("{")){
		return null;
	}
	
	var jsondata = new JSONObject(retStr);
	if(null == jsondata){
		return null;
	}
	var subtype = jsondata.get("subtype");
//	logger.info("Js parsed gprs_claa_locanchor subtype:" + subtype);
	if(1 == subtype){
		var devpowerjson = new JSONObject();//终端电量信息	
		devpowerjson.put("projectid", projectid);
		
		var labels = jsondata.get("labels");		
		if(null == labels || labels.length == 0){
			return null;
		}
		var labelsnum = labels.length/12;
		for(var i=0; i<labelsnum; i++){			
			var slabeldata = labels.substr(12*i,12);
			var labelid = slabeldata.substr(0,8);
			var rssi = slabeldata.substr(8,2);
			var voltlevel = slabeldata.substr(10,2);
			
			var locjson = new JSONObject();
			locjson.put("projectid", projectid);
			locjson.put("anchor_eui", anchor_eui);	
			locjson.put("lable_eui", "c1aa"+labelid.toLowerCase());
			locjson.put("rssi", rssi);
			locjson.put("voltlevel", voltlevel);
//			logger.info("Js parsed gprs_claa_locanchor locjson:" + locjson.toString());
			locrawdata.addBtAnchorData(locjson.toString());
			
			var btlabelpowerjson = new JSONObject();//构造标签电压等级对象,标签电量信息:{lable_eui:c1aa00001,curvollevel:1}		
			btlabelpowerjson.put("projectid", projectid);
			btlabelpowerjson.put("labeleui", labelid);
			btlabelpowerjson.put("curvoltage", voltlevel);
//			logger.info("Js parsed gprs_claa_locanchor btlabelpowerjson:" + btlabelpowerjson.toString());
			//蓝牙标签电压等级信息添加到队列里
			locrawdata.addLabelPowerData(btlabelpowerjson.toString());	
		}
		
	}else if(2 == subtype){
		var locjson = new JSONObject();	
		locjson.put("projectid", projectid);
		
		var gpslat = jsondata.get("gpslat");
		if(null == gpslat){
			gpslat = 254;
		}
		var gpslng = jsondata.get("gpslng");
		if(null == gpslng){
			gpslng = 254;
		}
		var batv = jsondata.get("batv");
		var gpsalt = jsondata.get("gpsalt");

		locjson.put("lat", gpslat);	
		locjson.put("lon", gpslng);
		locjson.put("type", 21);
		locjson.put("anchor_eui", anchor_eui);
		locjson.put("in_out_flag", 1); //0室内  1室外 
		locjson.put("cur_volt", batv);  //电压数据
		locrawdata.addGpsData(locjson.toString());
//		logger.info("Js parsed gprs_claa_locanchor locgpsjson:" + locjson.toString());
		
		var devpowerjson = new JSONObject();//终端电量信息	
		devpowerjson.put("projectid", projectid);
		devpowerjson.put("curvoltage", batv);
		locrawdata.addDevPowerData(devpowerjson.toString());
		
		var anchorgspdatajson = new JSONObject();//终端电量信息	
		anchorgspdatajson.put("deveui", anchor_eui);
		anchorgspdatajson.put("gpslat", gpslat);
		anchorgspdatajson.put("gpslng", gpslng);
		anchorgspdatajson.put("gpsalt", gpsalt);	
//		logger.info("Js parsed gprs_claa_locanchor anchorgspdatajson:" + anchorgspdatajson.toString());
		locrawdata.addCmNbAnchorGpsData(anchorgspdatajson.toString());
	}
	
	outMap.put('locrawdata', locrawdata);
	logger.info("Js parsed gprs_claa_locanchor outmap:" + outMap.toString());
	return outMap;	
}

function buildDevAckCmd(jsParam, appwrapper){	
	appwrapper.setAppeui(jsParam.getAppeui());
	appwrapper.setDeveui(jsParam.getDeveui());
	appwrapper.setDevtypeid(jsParam.getDevtypeid());
	appwrapper.setConfirm(false);
	appwrapper.setPort(jsParam.getDevport());	
	var appcmd =  new AppCommand();
	var str = new String("keepalive");
	appcmd.setCmd("ReplyHeartMsg");
	appcmd.appendPara("p1",str);
	appwrapper.setPayload(appcmd);
	return;
}

function ReplyHeartMsg(jsParam){
	var String = Java.type('java.lang.String');
	var logger = new LogPrint();	
	var cmdParaMap = jsParam.getParas();
	var str = cmdParaMap.get("p1");
	var jsontotal = new JSONObject();
	jsontotal.put("dt",8);
	var jsondata = new JSONObject();
	jsontotal.put("data",jsondata);
	jsondata.put("hb",str);
	var crc16code = getCrc16Code(jsondata.toString());
	jsontotal.put("crc",crc16code);		
	retstr = jsontotal.toString();
	logger.info("Js parsed gprs_claa_locanchor retstr:"+retstr);
	return retstr.getBytes("utf-8");
}

function checkCrcValid(srcstr,jsoncrc16code){
	var logger = new LogPrint();
	if(null == srcstr){
		return false;
	}
	var srclen = srcstr.length();;
	var matchstr = "\"data\":{";
	var matchlen = matchstr.length();
	var startidx = srcstr.indexOf(matchstr);
	var endidx = srcstr.indexOf("}",startidx+matchlen-1);
	var substr = srcstr.substring(startidx+matchlen-1,endidx+1);
	
	var hexstrtmp = "";
	for(var i=0; i<substr.length; i++){
        var charstr = substr.charAt(i);
        var charcode= charstr.charCodeAt();
        hexstrtmp += toHex(charcode & 0x00FF);
	}
	logger.info("Js parsed gprs_claa_locanchor data ascii str:"+hexstrtmp);
	
	//var sbuf = CRC16M.getSendBuf(hexstrtmp);  
	//var datastrafercrc16 = CRC16M.getBufHexStr(sbuf);	
	var crc16code = CRC16M.getCrc16CodeInt(hexstrtmp); 
	if(jsoncrc16code != crc16code){
		logger.info("Js parsed gprs_claa_locanchor targetcrc16:"+crc16code+",srccrc16code:"+jsoncrc16code);
		return false;
	}
	return true;
}

//设置设备上报周期
function SetRptCircle(jsParam){
	var logger = new LogPrint();
	var cmdParaMap = jsParam.getParas();
	var circle = cmdParaMap.get("rptcricle");
	var retstr = null;
	var jsontotal = new JSONObject();
	jsontotal.put("dt",2);	
	var jsondata = new JSONObject();
	jsontotal.put("data",jsondata);
	var dataisnotnull = 0;
	
	if(null != circle){
		if(circle<5)
		{
			circle = 5;
		}
		else if(circle>86400)
		{
			circle = 86400;
		}
		jsondata.put("rptcricle",circle);
		dataisnotnull = 1;
	}	
	if(1 == dataisnotnull){
		var crc16code = getCrc16Code(jsondata.toString());
		jsontotal.put("crc",crc16code);		
		retstr = jsontotal.toString();
		logger.info("Js parsed gprs_claa_locanchor retstr:"+retstr);
		return retstr.getBytes("utf-8");
	}
	return null;
}

//设置设备心跳周期
function SetHBCircle(jsParam){
	var logger = new LogPrint();
	var cmdParaMap = jsParam.getParas();
	var circle = cmdParaMap.get("hbcricle");
	var retstr = null;
	var jsontotal = new JSONObject();
	jsontotal.put("dt",2);	
	var jsondata = new JSONObject();
	jsontotal.put("data",jsondata);
	var dataisnotnull = 0;
	
	if(null != circle){
		if(circle<5)
		{
			circle = 5;
		}
		else if(circle>86400)
		{
			circle = 86400;
		}
		jsondata.put("hbcricle",circle);
		dataisnotnull = 1;
	}	
	if(1 == dataisnotnull){
		var crc16code = getCrc16Code(jsondata.toString());
		jsontotal.put("crc",crc16code);		
		retstr = jsontotal.toString();
		logger.info("Js parsed gprs_claa_locanchor retstr:"+retstr);
		return retstr.getBytes("utf-8");
	}
	return null;
}

function getCrc16Code(datastr){
	if(null == datastr){
		return null;
	}
	var hexstrtmp = "";
	for(var i=0; i<datastr.length; i++){
        var str = datastr.charAt(i);
        var charcode= str.charCodeAt();
        hexstrtmp += toHex(charcode & 0x00FF);
	}
	var crc16code = CRC16M.getCrc16CodeInt(hexstrtmp);  
	return crc16code;
}

//将一个数字转化成16进制字符串形式
function toHex(num){
	return num<16?"0"+num.toString(16):num.toString(16);
}
